﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using JCPogi.Core.Helpers;

namespace JCPogi.Core {
    public abstract class DeviceCommandContext : IDisposable {

        public DeviceCommandContext(CommunicationDevice communicationDevice) {   
            Device = communicationDevice;
        }

        protected CommunicationDevice Device { get; private set; }

        public virtual void PerformCommandAsync(Action<DeviceCommandResult> onCompleted, Action<string> onPublishUpdate) {
            Protect.AgainstInvalidOperation(_worker != null, "Command is already running asynchronously");

            _onCompleted = onCompleted;
            _onPublishUpdate = onPublishUpdate;

            _worker = new AbortableBackgroundWorker { WorkerSupportsCancellation = true };
            _worker.DoWork += (sender, e) => e.Result = PerformCommand(new PerformCommandContext(onPublishUpdate, e));
            _worker.RunWorkerCompleted += (sender, e) => {
                var commandResult = e.Cancelled ? null : (DeviceCommandResult)e.Result;

                string errorMessage = null;
                if (!commandResult.IsNull()) {
                    errorMessage = e.Error.IsNull() ? commandResult.ErrorMessage : e.Error.ToString();
                }
                
                _onCompleted(new DeviceCommandResult(errorMessage));
                _worker.Dispose();
                _worker = null;
            };

            _worker.RunWorkerAsync();
        }

        public virtual void StopAsyncCommand() {
            if (_worker == null) return; // not running async.

            if (_worker.IsRunning)
                _worker.Abort();
        }

        public abstract DeviceCommandResult PerformCommand(PerformCommandContext context);

        #region IDisposable

        public void Dispose() {
            Device.Dispose();
            Device = null;
        }

        #endregion

        private AbortableBackgroundWorker _worker = null;
        private Action<DeviceCommandResult> _onCompleted;
        private Action<string> _onPublishUpdate;
    }
}
